package com.xaicode.ca;

import com.isoftstone.vsm.base.BaseRepository;
import com.isoftstone.vsm.config.properties.CAProperties;
import com.isoftstone.vsm.modules.vsm.tenant.entity.TenantVrfEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author Locker xaicode@sina.com
 */
@Service
@Slf4j
public class CaServiceImpl implements ICaService {

    @Value("${security.ca.vsmDN}")
    private String vsmDN;

    @Value("${security.ca.deviceDN}")
    private String caDeviceDN;

    private final CaRepository caRepository;

    private final CertificationAuthority certificationAuthority;

    private final CAProperties caProperties;

    public CaServiceImpl(CaRepository caRepository, CertificationAuthority certificationAuthority, CAProperties caProperties) {
        this.caRepository = caRepository;
        this.certificationAuthority = certificationAuthority;
        this.caProperties = caProperties;
    }

    @Override
    public BaseRepository<CaEntity, String> getRepository() {
        return caRepository;
    }

    @Override
    public CaEntity rootCA() {
        return caRepository.rootCA();
    }

    /**
     * 创建CA证书
     *
     * @param clientDN           客户专用名称，
     *                           此处应用与设备端和移动端商定的规则，即使用租户服务中设备关联的租户路由域的发送id
     * @param deviceSerialNumber 设备序列号
     * @param tenantVrfId        租户路由域id
     * @param vrfId              同 clientDistinguishedName
     * @param startTime          证书启用时间，null 为立即生效
     * @param endTime            证书失效时间，null 为使用配置文件的签发日期
     * @return .
     * @see TenantVrfEntity#getIndexToSend()
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public CaEntity createCA(String clientDN, String deviceSerialNumber, String tenantVrfId, Integer vrfId,
                             Long startTime, Long endTime) {

        CaEntity rootCA = caRepository.rootCA();
        if (null == rootCA) {
            throw new RuntimeException("- require root CA, need to init root CA first");
        }

        // 设备已存在证书校验
        CaEntity existCA = caRepository.findByDeviceSerialNumber(deviceSerialNumber);
        if (null != existCA && existCA.getTenantVrfId().equals(tenantVrfId) && existCA.getVrfId().equals(vrfId)) {
            log.warn("- current device has one CA already with deviceSerialNumber={}, tenantVrfId={}, vrfId={}",
                    deviceSerialNumber, tenantVrfId, vrfId);
            return null;
        }

        CaEntity largestSerialNumberCa = caRepository.findTopByOrderBySerialNumberDesc();
        if (null == startTime) {
            startTime = System.currentTimeMillis();
        }
        if (null == endTime) {
            endTime = startTime + caProperties.getSignValidity() * 86400000L;
        }

//        String caDistinguishedName = "OU=" + rootCA.getOrganizationUnit() +
//                ",O=" + rootCA.getOrganization() +
//                ",L=" + rootCA.getLocality() +
//                ",ST=" + rootCA.getState() +
//                ",C=" + rootCA.getCommonName();

        // TODO 设备端要求：CN 需以字符串 "vrf_" + vrf_send_index 组成
        if (!clientDN.startsWith("vrf_")) {
            clientDN = "vrf_" + clientDN;
        }

        CertificateAndKey certificateAndKey = certificationAuthority.create(
                rootCA.getPrivateKey(),
                caDeviceDN + ", CN=" + clientDN,
                vsmDN,
                largestSerialNumberCa.getSerialNumber() + 1,
                startTime, endTime);

        CaEntity caEntity = new CaEntity();

        caEntity.setCountryName(rootCA.getCountryName());
        caEntity.setCommonName(rootCA.getCommonName());
        caEntity.setOrganizationUnit(clientDN);
        caEntity.setOrganization(clientDN);
        caEntity.setLocality(rootCA.getLocality());
        caEntity.setState(rootCA.getState());
        caEntity.setKeySize(rootCA.getKeySize());
        caEntity.setSignAlgorithm(rootCA.getSignAlgorithm());
        caEntity.setSignValidity(rootCA.getSignValidity());

        caEntity.setCertificate(certificateAndKey.getCertificate());
        caEntity.setPublicKey(certificateAndKey.getBase64Key().getBase64PublicKey());
        caEntity.setPrivateKey(certificateAndKey.getBase64Key().getBase64PrivateKey());
        caEntity.setStartTime(startTime);
        caEntity.setEndTime(endTime);
        caEntity.setLevel(rootCA.getLevel() + 1);
        caEntity.setSerialNumber(largestSerialNumberCa.getSerialNumber() + 1L);
        caEntity.setParentId(rootCA.getId());

        caEntity.setDeviceSerialNumber(deviceSerialNumber);
        caEntity.setTenantVrfId(tenantVrfId);
        caEntity.setVrfId(vrfId);

        return caRepository.save(caEntity);
    }

    @Override
    public CaEntity findByDeviceSerialNumber(String deviceSerialNumber) {
        return caRepository.findByDeviceSerialNumber(deviceSerialNumber);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CaEntity deleteCA(String deviceSerialNumber) {
        CaEntity caEntity = caRepository.findByDeviceSerialNumber(deviceSerialNumber);
        if (null != caEntity) {
            caRepository.delete(caEntity);
            return caEntity;
        }
        return null;
    }

}
